﻿using FFmpeg.AutoGen;
using System;

namespace FFmpegLib
{
    public sealed unsafe class FAVFrame : IDisposable
    {
        public static readonly AVRational TimeBaseQ = new AVRational { num = 1, den = ffmpeg.AV_TIME_BASE };

        private AVFrame* _ptr;
        public AVFrame* Ptr { get => _ptr; }
        public AVMediaType MediaType = AVMediaType.AVMEDIA_TYPE_UNKNOWN;

        /// <summary>
        /// it is valid when MediaType is audio
        /// </summary>
        public AVSampleFormat AudioFormat { get { return (AVSampleFormat)_ptr->format; } }

        /// <summary>
        /// it is valid when MediaType type is video
        /// </summary>
        public AVPixelFormat VideoFormat { get { return (AVPixelFormat)_ptr->format; } }

        public int Width
        {
            get { return _ptr->width; }
            set { _ptr->width = value; }
        }

        public int Height
        {
            get { return _ptr->height; }
            set { _ptr->height = value; }
        }

        public int SampleRate
        {
            get { return _ptr->sample_rate; }
        }

        public int NbSamples
        {
            get { return _ptr->nb_samples; }
        }

        public int Channels
        {
            get { return _ptr->channels; }
        }

        public ulong ChannelLayout
        {
            get { return _ptr->channel_layout; }
        }

        public int Format
        {
            get { return _ptr->format; }
        }

        public long Pts
        {
            get { return _ptr->pts; }
        }

        public long newPts = -1;
        /// <summary>
        /// 单位 ms
        /// </summary>
        public long NewPts
        {
            get
            {
                if (newPts == -1)
                    InitNewPts();
                return newPts;
            }
            private set { newPts = value; }
        }

        public AVRational TimeBase { get; set; }

        public FAVFrame()
        {
            _ptr = ffmpeg.av_frame_alloc();
        }

        public FAVFrame(AVFrame* frame)
        {
            this._ptr = frame;
        }

        public FAVFrame(IntPtr pFrame)
        {
            _ptr = (AVFrame*)pFrame;
        }

        public long InitNewPts(AVRational? timeBase = null)
        {
            if (timeBase.HasValue)
            {
                TimeBase = timeBase.Value;
                return NewPts = ffmpeg.av_rescale_q(_ptr->pts, timeBase.Value, TimeBaseQ) / 1000;
            }
            return NewPts = ffmpeg.av_rescale_q(_ptr->pts, TimeBase, TimeBaseQ) / 1000;
        }

        public void UnRef()
        {
            if (_ptr != null) ffmpeg.av_frame_unref(_ptr);
        }

        public void Ref(AVFrame* src)
        {
            if (_ptr != null) ffmpeg.av_frame_ref(_ptr, src);
        }

        #region dispose
        private bool disposedValue;
        protected void Dispose(bool disposing)
        {
            if (!disposedValue)
            {
                if (disposing)
                {
                    ffmpeg.av_frame_unref(_ptr);
                    fixed (AVFrame** ptr = &_ptr)
                        ffmpeg.av_frame_free(ptr);
                    _ptr = null;
                }
                disposedValue = true;
            }
        }

        public void Dispose()
        {
            // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }
        #endregion

    }
}